Coverage Report

Created: 2025-05-27 14:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\vk-layer-for-rust\vk-layer-for-rust\vulkan-layer\src\lib.rs
Line
Count
Source
1
// Copyright 2023 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#![warn(missing_docs)]
16
#![cfg_attr(all(doc, RUSTC_NIGHTLY), feature(doc_auto_cfg))]
17
18
//! This crate provides a convenient framework to develop
19
//! [Vulkan layers](https://github.com/KhronosGroup/Vulkan-Loader/blob/main/docs/LoaderLayerInterface.md)
20
//! in Rust on top of the [ash](https://crates.io/crates/ash) crate. If you are not familiar how to
21
//! write a Vulkan layer, [this C++ tutorial](https://renderdoc.org/vulkan-layer-guide.html) by
22
//! Baldur Karlsson is a good reference to start with.
23
//!
24
//! Key features provided by this crate includes:
25
//!
26
//! * Support the look-up map fashion of implementing a Vulkan layer.
27
//!
28
//!   The look-up maps for `VkDevice` and `VkInstance` are handled by this crate.
29
//!
30
//! * Implement `vkGet*ProcAddr` automatically.
31
//!
32
//!   This is a non-trivial work to comply with the spec, because of extensions and the
33
//!   required/supported Vulkan API level. See the
34
//!   [spec](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html)
35
//!   of `vkGetInstanceProc` for details.
36
//!
37
//! * Handle dispatch tables, `vkCreateInstance` and `vkCreateDevice`.
38
//!
39
//!   This mainly includes using the `vkGet*ProcAddr` function pointer correctly, and advancing the
40
//!   `VkLayer*CreateInfo::u::pLayerInfo` link list. One common mistake in layer implementation
41
//!   in `vkCreateDevice` is to call `getInstanceProcAddr(VK_NULL_HANDLE, "vkCreateDevice")` to
42
//!   obtain the function pointer to `vkCreateDevice`. According to
43
//!   [the spec](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#_description),
44
//!   `getInstanceProcAddr` should return `NULL`. This framework helps you avoid bugs like this.
45
//!
46
//! Note that object wrapping is not supported by this crate, and we don't plan such support,
47
//! because object wrapping requires us to intercept ALL Vulkan commands related to one handle type,
48
//! so it can't handle unknown commands. In addition, object wrapping is more complicated because it
49
//! is required to call loader callback on every dispatchable handle creation and destruction.
50
//!
51
//! # Overview
52
//!
53
//! The primary types in this crate are the [`Layer`] trait and the [`Global`] struct. The user
54
//! implements the [`Layer`] trait for a type `T`, and the [`Global<T>`] will include all necessary
55
//! functions needed to export from this dynamic link library. With the help of the
56
//! [`declare_introspection_queries`] macro, the user can export those functions in oneline.
57
//!
58
//! ```
59
//! use ash::{self, vk};
60
//! use once_cell::sync::Lazy;
61
//! use std::sync::Arc;
62
//! use vulkan_layer::{
63
//!     declare_introspection_queries, Global, Layer, LayerManifest, StubDeviceInfo,
64
//!     StubGlobalHooks, StubInstanceInfo,
65
//! };
66
//!
67
//! // Define the layer type.
68
//! #[derive(Default)]
69
//! struct MyLayer(StubGlobalHooks);
70
//!
71
//! // Implement the Layer trait.
72
//! impl Layer for MyLayer {
73
//!     type GlobalHooksInfo = StubGlobalHooks;
74
//!     type InstanceInfo = StubInstanceInfo;
75
//!     type DeviceInfo = StubDeviceInfo;
76
//!     type InstanceInfoContainer = StubInstanceInfo;
77
//!     type DeviceInfoContainer = StubDeviceInfo;
78
//!
79
//!     fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static {
80
//!         static GLOBAL: Lazy<Global<MyLayer>> = Lazy::new(Default::default);
81
//!         &*GLOBAL
82
//!     }
83
//!
84
//!     fn manifest() -> LayerManifest {
85
//!         Default::default()
86
//!     }
87
//!
88
//!     fn global_hooks_info(&self) -> &Self::GlobalHooksInfo {
89
//!         &self.0
90
//!     }
91
//!
92
//!     fn create_instance_info(
93
//!         &self,
94
//!         _: &vk::InstanceCreateInfo,
95
//!         _: Option<&vk::AllocationCallbacks>,
96
//!         _: Arc<ash::Instance>,
97
//!         _next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
98
//!     ) -> Self::InstanceInfoContainer {
99
//!         Default::default()
100
//!     }
101
//!
102
//!     fn create_device_info(
103
//!         &self,
104
//!         _: vk::PhysicalDevice,
105
//!         _: &vk::DeviceCreateInfo,
106
//!         _: Option<&vk::AllocationCallbacks>,
107
//!         _: Arc<ash::Device>,
108
//!         _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
109
//!     ) -> Self::DeviceInfoContainer {
110
//!         Default::default()
111
//!     }
112
//! }
113
//!
114
//! // Define the global type from the layer type.
115
//! type MyGlobal = Global<MyLayer>;
116
//! // Export C functions.
117
//! declare_introspection_queries!(MyGlobal);
118
//! ```
119
//! The user can provide their own types that implement different traits to intercept different
120
//! commands and custom the layer behavior:
121
//! * [`GlobalHooks`], [`InstanceHooks`], [`DeviceHooks`]: Implements the interception to different
122
//!   Vulkan commands based on the dispatch types.
123
//! * [`GlobalHooksInfo`], [`InstanceInfo`], [`DeviceInfo`]: Container of [`GlobalHooks`],
124
//!   [`InstanceHooks`], [`DeviceHooks`]. Provide the list of commands to intercept for the
125
//!   framework. Can be automatically implemented through the [`auto_deviceinfo_impl`],
126
//!   [`auto_globalhooksinfo_impl`], [`auto_instanceinfo_impl`] macros from the [`GlobalHooks`],
127
//!   [`InstanceHooks`], [`DeviceHooks`] implementation respectively.
128
//! * [`Layer`]: Provide the metadata of a layer through [`LayerManifest`], e.g. the name, version,
129
//!   exported extensions of the layer. Provide the storage for the [`Global`] object. Container of
130
//!   [`GlobalHooksInfo`] type. The factory type of the [`InstanceInfo`], [`DeviceInfo`] types.
131
//!
132
//! # Usage
133
//!
134
//! You can check a live example in `examples/hello-world`.
135
//!
136
//! First, create a Rust lib crate.
137
//! ```bash
138
//! $ mkdir vulkan-layer-rust-example
139
//! $ cd vulkan-layer-rust-example
140
//! $ cargo init --lib
141
//!      Created library package
142
//! ```
143
//!
144
//! Second, modify the crate type to `cdylib` and set the panic behavior to abort in `Cargo.toml`.
145
//! ```toml
146
//! [lib]
147
//! crate-type = ["cdylib"]
148
//!
149
//! [profile.dev]
150
//! panic = "abort"
151
//!
152
//! [profile.release]
153
//! panic = "abort"
154
//! ```
155
//! We need to set panic to abort to avoid unwinding from Rust to the caller(most likely C/C++),
156
//! because unwinding into other language from Rust is
157
//! [undefined behavior](https://doc.rust-lang.org/beta/nomicon/unwinding.html).
158
//!
159
//! If you want to try the layer on Android, also modify the crate name to
160
//! `VkLayer_vendor_rust_example`, because Android requires that the layer shared object library
161
//! follow a specific name convention.
162
//! ```toml
163
//! [lib]
164
//! name = "VkLayer_vendor_rust_example"
165
//! ```
166
//!
167
//! Third, set up the dependency in `Cargo.toml`. In my case, I checkout the project repository in
168
//! the same directory where the `vulkan-layer-rust-example` folder lives.
169
//! ```toml
170
//! [dependencies]
171
//! vulkan-layer = { path = "../vk-layer-for-rust/vulkan-layer" }
172
//! ```
173
//! Other dependencies.
174
//! ```bash
175
//! cargo add ash once_cell
176
//! ```
177
//!
178
//! Fourth, implement the layer trait in `lib.rs`.
179
//! ```
180
//! use ash::{self, vk};
181
//! use once_cell::sync::Lazy;
182
//! use std::sync::Arc;
183
//! use vulkan_layer::{
184
//!     declare_introspection_queries, Global, Layer, LayerManifest, StubDeviceInfo,
185
//!     StubGlobalHooks, StubInstanceInfo,
186
//! };
187
//!
188
//! #[derive(Default)]
189
//! struct MyLayer(StubGlobalHooks);
190
//!
191
//! impl Layer for MyLayer {
192
//!     type GlobalHooksInfo = StubGlobalHooks;
193
//!     type InstanceInfo = StubInstanceInfo;
194
//!     type DeviceInfo = StubDeviceInfo;
195
//!     type InstanceInfoContainer = StubInstanceInfo;
196
//!     type DeviceInfoContainer = StubDeviceInfo;
197
//!
198
//!     fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static {
199
//!         static GLOBAL: Lazy<Global<MyLayer>> = Lazy::new(Default::default);
200
//!         &*GLOBAL
201
//!     }
202
//!
203
//!     fn manifest() -> LayerManifest {
204
//!         let mut manifest = LayerManifest::default();
205
//!         manifest.name = "VK_LAYER_VENDOR_rust_example";
206
//!         manifest.spec_version = vk::API_VERSION_1_1;
207
//!         manifest.description = "Rust test layer";
208
//!         manifest
209
//!     }
210
//!
211
//!     fn global_hooks_info(&self) -> &Self::GlobalHooksInfo {
212
//!         &self.0
213
//!     }
214
//!
215
//!     fn create_instance_info(
216
//!         &self,
217
//!         _: &vk::InstanceCreateInfo,
218
//!         _: Option<&vk::AllocationCallbacks>,
219
//!         _: Arc<ash::Instance>,
220
//!         _next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
221
//!     ) -> Self::InstanceInfoContainer {
222
//!         Default::default()
223
//!     }
224
//!
225
//!     fn create_device_info(
226
//!         &self,
227
//!         _: vk::PhysicalDevice,
228
//!         _: &vk::DeviceCreateInfo,
229
//!         _: Option<&vk::AllocationCallbacks>,
230
//!         _: Arc<ash::Device>,
231
//!         _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
232
//!     ) -> Self::DeviceInfoContainer {
233
//!         println!("Hello from the Rust Vulkan layer!");
234
//!         Default::default()
235
//!     }
236
//! }
237
//! ```
238
//!
239
//! Fifth, export functions through the [`declare_introspection_queries`] macro
240
//! ```
241
//! # use ash::{self, vk};
242
//! # use once_cell::sync::Lazy;
243
//! # use std::sync::Arc;
244
//! # use vulkan_layer::{
245
//! #     declare_introspection_queries, Global, Layer, LayerManifest, StubDeviceInfo,
246
//! #     StubGlobalHooks, StubInstanceInfo,
247
//! # };
248
//! #
249
//! # #[derive(Default)]
250
//! # struct MyLayer(StubGlobalHooks);
251
//! #
252
//! # impl Layer for MyLayer {
253
//! #     type GlobalHooksInfo = StubGlobalHooks;
254
//! #     type InstanceInfo = StubInstanceInfo;
255
//! #     type DeviceInfo = StubDeviceInfo;
256
//! #     type InstanceInfoContainer = StubInstanceInfo;
257
//! #     type DeviceInfoContainer = StubDeviceInfo;
258
//! #
259
//! #     fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static {
260
//! #         static GLOBAL: Lazy<Global<MyLayer>> = Lazy::new(Default::default);
261
//! #         &*GLOBAL
262
//! #     }
263
//! #
264
//! #     fn manifest() -> LayerManifest {
265
//! #         let mut manifest = LayerManifest::default();
266
//! #         manifest.name = "VK_LAYER_VENDOR_rust_example";
267
//! #         manifest.spec_version = vk::API_VERSION_1_1;
268
//! #         manifest.description = "Rust test layer";
269
//! #         manifest
270
//! #     }
271
//! #
272
//! #     fn global_hooks_info(&self) -> &Self::GlobalHooksInfo {
273
//! #         &self.0
274
//! #     }
275
//! #
276
//! #     fn create_instance_info(
277
//! #         &self,
278
//! #         _: &vk::InstanceCreateInfo,
279
//! #         _: Option<&vk::AllocationCallbacks>,
280
//! #         _: Arc<ash::Instance>,
281
//! #         _next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
282
//! #     ) -> Self::InstanceInfoContainer {
283
//! #         Default::default()
284
//! #     }
285
//! #
286
//! #     fn create_device_info(
287
//! #         &self,
288
//! #         _: vk::PhysicalDevice,
289
//! #         _: &vk::DeviceCreateInfo,
290
//! #         _: Option<&vk::AllocationCallbacks>,
291
//! #         _: Arc<ash::Device>,
292
//! #         _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
293
//! #     ) -> Self::DeviceInfoContainer {
294
//! #         println!("Hello from the Rust Vulkan layer!");
295
//! #         Default::default()
296
//! #     }
297
//! # }
298
//! declare_introspection_queries!(Global::<MyLayer>);
299
//! ```
300
//!
301
//! Sixth, build and check the exported symbol of the build artifacts, and we should see Vulkan
302
//! introspection APIs are exported.
303
//!
304
//! On Windows, use
305
//! [`dumpbin`](https://learn.microsoft.com/en-us/cpp/build/reference/dumpbin-reference?view=msvc-170)
306
//! ```cmd
307
//! $ dumpbin /exports .\target\debug\VkLayer_vendor_rust_example.dll
308
//! Microsoft (R) COFF/PE Dumper Version 14.36.32537.0
309
//! Copyright (C) Microsoft Corporation.  All rights reserved.
310
//!
311
//!
312
//! Dump of file .\target\debug\VkLayer_vendor_rust_example.dll
313
//!
314
//! File Type: DLL
315
//!
316
//!   Section contains the following exports for VkLayer_vendor_rust_example.dll
317
//!
318
//!     00000000 characteristics
319
//!     FFFFFFFF time date stamp
320
//!         0.00 version
321
//!            1 ordinal base
322
//!            6 number of functions
323
//!            6 number of names
324
//!
325
//!     ordinal hint RVA      name
326
//!
327
//!           1    0 000F1840 vkEnumerateDeviceExtensionProperties = vkEnumerateDeviceExtensionProperties
328
//!           2    1 000F1820 vkEnumerateDeviceLayerProperties = vkEnumerateDeviceLayerProperties
329
//!           3    2 000F1800 vkEnumerateInstanceExtensionProperties = vkEnumerateInstanceExtensionProperties
330
//!           4    3 000F17E0 vkEnumerateInstanceLayerProperties = vkEnumerateInstanceLayerProperties
331
//!           5    4 000F1890 vkGetDeviceProcAddr = vkGetDeviceProcAddr
332
//!           6    5 000F1870 vkGetInstanceProcAddr = vkGetInstanceProcAddr
333
//!
334
//!   Summary
335
//!
336
//!         1000 .data
337
//!        11000 .pdata
338
//!        37000 .rdata
339
//!         2000 .reloc
340
//!       171000 .text
341
//! ```
342
//! On Linux, use [`objdump`](https://linux.die.net/man/1/objdump).
343
//! ```bat
344
//! $ objdump -TC target/debug/libVkLayer_vendor_rust_example.so
345
//!
346
//! target/debug/libVkLayer_vendor_rust_example.so:     file format elf64-x86-64
347
//!
348
//! DYNAMIC SYMBOL TABLE:
349
//! (omit some irrelevant symbols...)
350
//! 00000000000fad20 g    DF .text  0000000000000022  Base        vkEnumerateDeviceExtensionProperties
351
//! 00000000000face0 g    DF .text  000000000000001c  Base        vkEnumerateInstanceExtensionProperties
352
//! 00000000000fad50 g    DF .text  0000000000000018  Base        vkGetInstanceProcAddr
353
//! 00000000000facc0 g    DF .text  0000000000000018  Base        vkEnumerateInstanceLayerProperties
354
//! 00000000000fad00 g    DF .text  000000000000001c  Base        vkEnumerateDeviceLayerProperties
355
//! 00000000000fad70 g    DF .text  0000000000000018  Base        vkGetDeviceProcAddr
356
//! ```
357
//!
358
//! Seventh, create the layer manifest file named `rust_example_layer.json` right beside the built
359
//! artifact. If targeting Android, the json manifest file is not needed.
360
//!
361
//! For Windows,
362
//! ```json
363
//! {
364
//!     "file_format_version" : "1.2.1",
365
//!     "layer": {
366
//!         "name": "VK_LAYER_VENDOR_rust_example",
367
//!         "type": "INSTANCE",
368
//!         "library_path": ".\\VkLayer_vendor_rust_example.dll",
369
//!         "library_arch" : "64",
370
//!         "api_version" : "1.1.0",
371
//!         "implementation_version" : "0",
372
//!         "description" : "Rust test layer"
373
//!     }
374
//! }
375
//! ```
376
//!
377
//! For Linux,
378
//! ```json
379
//! {
380
//!     "file_format_version" : "1.2.1",
381
//!     "layer": {
382
//!         "name": "VK_LAYER_VENDOR_rust_example",
383
//!         "type": "INSTANCE",
384
//!         "library_path": "./libVkLayer_vendor_rust_example.so",
385
//!         "library_arch" : "64",
386
//!         "api_version" : "1.1.0",
387
//!         "implementation_version" : "0",
388
//!         "description" : "Rust test layer"
389
//!     }
390
//! }
391
//! ```
392
//! This json file will define an explicit layer named `VK_LAYER_VENDOR_rust_example`.
393
//!
394
//! Eighth, use [`VkConfig`](https://github.com/LunarG/VulkanTools/blob/main/vkconfig/README.md)
395
//! (i.e. Vulkan Configurator) to force enable this explicit layer, and launch the vkcube
396
//! application through `VkConfig`. In the log view, we should see the
397
//! `"Hello from the Rust Vulkan layer!"` log line. For Android, follow
398
//! [this instruction](https://developer.android.com/ndk/guides/graphics/validation-layer) to enable
399
//! the layer. [`println!`] won't write to logcat, so one needs to change the layer implementation
400
//! to write to the logcat.
401
//!
402
//! # Global initialization and clean up
403
//!
404
//! See [the][Layer#initialization] [document][Layer#global-clean-up] of [`Layer`] for details.
405
//!
406
//! # Extensions
407
//!
408
//! TODO
409
//!
410
//! # Synchronization
411
//!
412
//! TODO
413
//!
414
//! # Safety
415
//!
416
//! TODO
417
//!
418
//! # API stability
419
//!
420
//! TODO
421
422
use ash::vk::{self, Handle};
423
use bytemuck::cast_slice;
424
use log::{error, warn};
425
use std::{
426
    borrow::Borrow,
427
    collections::{BTreeMap, BTreeSet},
428
    ffi::{c_char, c_void, CStr, CString},
429
    ptr::{null, null_mut, NonNull},
430
    sync::{Arc, Mutex},
431
};
432
extern crate self as vulkan_layer;
433
434
mod bindings;
435
mod global_simple_intercept;
436
mod layer_trait;
437
mod lazy_collection;
438
#[cfg(any(feature = "_test", test))]
439
pub mod test_utils;
440
441
#[cfg(feature = "unstable")]
442
pub mod unstable_api;
443
#[cfg(not(feature = "unstable"))]
444
mod unstable_api;
445
mod vk_utils;
446
447
use bindings::vk_layer::{VkLayerDeviceCreateInfo, VkLayerFunction, VkLayerInstanceCreateInfo};
448
pub use bindings::vk_layer::{VkLayerDeviceLink, VkLayerInstanceLink};
449
pub use global_simple_intercept::Extension;
450
use global_simple_intercept::{DeviceDispatchTable, InstanceDispatchTable, VulkanCommand};
451
pub use layer_trait::{
452
    DeviceHooks, DeviceInfo, ExtensionProperties, GlobalHooks, GlobalHooksInfo, InstanceHooks,
453
    InstanceInfo, Layer, LayerManifest, LayerResult, VulkanCommand as LayerVulkanCommand,
454
};
455
use unstable_api::{ApiVersion, IsCommandEnabled, LazyCollection};
456
pub use vk_utils::{fill_vk_out_array, VulkanBaseInStructChain, VulkanBaseOutStructChain};
457
use vk_utils::{ptr_as_uninit_mut, slice_from_raw_parts, slice_to_owned_strings};
458
pub use vulkan_layer_macros::{
459
    auto_deviceinfo_impl, auto_globalhooksinfo_impl, auto_instanceinfo_impl,
460
    declare_introspection_queries,
461
};
462
463
trait DispatchableObject: vk::Handle + Copy {
464
    type DispatchKey: From<usize>;
465
466
7.21k
    fn get_dispatch_key(&self) -> Self::DispatchKey {
467
7.21k
        assert_eq!(
468
7.21k
            std::mem::size_of::<Self>(),
469
7.21k
            std::mem::size_of::<*const *const c_void>()
470
7.21k
        );
471
        // Safe, because all dispatchable objects can be cast to void **. See details at
472
        // https://github.com/KhronosGroup/Vulkan-Loader/blob/35b005a5792f6e4c2931d62a37324923f1a71c79/docs/LoaderDriverInterface.md#driver-dispatchable-object-creation.
473
7.21k
        let key = unsafe {
474
7.21k
            // We use transmute instead of Handle::as_raw here to avoid integer to pointer cast, and
475
7.21k
            // allow the miri tests with tree borrows to work with this test. See
476
7.21k
            // https://github.com/ash-rs/ash/issues/996 for details.
477
7.21k
            let dispatch_table_ptr = std::mem::transmute_copy::<Self, *const *const c_void>(self);
478
7.21k
            std::ptr::read(dispatch_table_ptr)
479
7.21k
        };
480
7.21k
        (key as usize).into()
481
7.21k
    }
482
}
483
484
#[repr(transparent)]
485
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
486
struct InstanceDispatchKey(usize);
487
488
impl From<usize> for InstanceDispatchKey {
489
1.92k
    fn from(value: usize) -> Self {
490
1.92k
        Self(value)
491
1.92k
    }
492
}
493
494
impl DispatchableObject for vk::Instance {
495
    type DispatchKey = InstanceDispatchKey;
496
}
497
498
impl DispatchableObject for vk::PhysicalDevice {
499
    type DispatchKey = InstanceDispatchKey;
500
}
501
502
#[repr(transparent)]
503
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
504
struct DeviceDispatchKey(usize);
505
506
impl From<usize> for DeviceDispatchKey {
507
5.29k
    fn from(value: usize) -> Self {
508
5.29k
        Self(value)
509
5.29k
    }
510
}
511
512
impl DispatchableObject for vk::Device {
513
    type DispatchKey = DeviceDispatchKey;
514
}
515
516
impl DispatchableObject for vk::CommandBuffer {
517
    type DispatchKey = DeviceDispatchKey;
518
}
519
520
impl DispatchableObject for vk::Queue {
521
    type DispatchKey = DeviceDispatchKey;
522
}
523
524
struct InstanceInfoWrapper<T: Layer> {
525
    get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
526
    dispatch_table: InstanceDispatchTable,
527
    api_version: ApiVersion,
528
    enabled_extensions: BTreeSet<Extension>,
529
    // instance_commands and device_commands are recalculated on every vkCreateInstance, so that
530
    // the layer can decide which commands to intercept dynamically.
531
    instance_commands: Box<[VulkanCommand]>,
532
    device_commands: Box<[VulkanCommand]>,
533
    is_create_device_hooked: bool,
534
    customized_info: T::InstanceInfoContainer,
535
}
536
537
struct PhysicalDeviceInfoWrapper {
538
    owner_instance: vk::Instance,
539
    properties: vk::PhysicalDeviceProperties,
540
}
541
542
struct DeviceInfoWrapper<T: Layer> {
543
    dispatch_table: DeviceDispatchTable,
544
    get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
545
    api_version: ApiVersion,
546
    enabled_extensions: BTreeSet<Extension>,
547
    // device_commands are recalculated on every vkCreateDevice, so that the layer can decide
548
    // which commands to intercept dynamically.
549
    device_commands: Box<[VulkanCommand]>,
550
    customized_info: T::DeviceInfoContainer,
551
}
552
553
/// A struct that implements all necessarily functions for a layer given a type that implements
554
/// [`Layer`].
555
///
556
/// The layer implementation should use [`Global::default`] to construct a [`Global`] object.
557
/// When all `VkInstance`s and `VkDevice`s are destroyed, the drop of [`Global`] is no-op if the
558
/// drop of `T` is no-op under such circumstances. See [the][Layer#initialization]
559
/// [document][Layer#global-clean-up] of [`Layer`] for details on global initialization and
560
/// clean-up.
561
///
562
/// This is supposed to be a global singleton for a layer to store all necessary data to implement a
563
/// Vulkan layer including dispatch tables, maps between the Vulkan objects and their wrappers, etc.
564
pub struct Global<T: Layer> {
565
    instance_map: Mutex<LazyCollection<BTreeMap<InstanceDispatchKey, Arc<InstanceInfoWrapper<T>>>>>,
566
    physical_device_map:
567
        Mutex<LazyCollection<BTreeMap<vk::PhysicalDevice, Arc<PhysicalDeviceInfoWrapper>>>>,
568
    device_map: Mutex<LazyCollection<BTreeMap<DeviceDispatchKey, Arc<DeviceInfoWrapper<T>>>>>,
569
    /// Access to the underlying `T`.
570
    // layer_info can't be lazily constructed when the first VkInstance is created, because we want
571
    // to guarantee that T::default is only called once during the lifetime of Global, so that the
572
    // client can put global state in T, and can perform global initialization(e.g. the global
573
    // logger) in T::default. If the client needs Global to be trivially destructible, the client
574
    // must guarantee that T is also trivially destructible.
575
    pub layer_info: T,
576
    get_instance_addr_proc_hooked: bool,
577
}
578
579
impl<T: Layer> Global<T> {
580
7.54k
    fn instance() -> impl std::ops::Deref<Target = Self> + 'static {
581
7.54k
        T::global_instance()
582
7.54k
    }
583
584
1.82k
    fn get_instance_info(
585
1.82k
        &self,
586
1.82k
        instance: impl DispatchableObject<DispatchKey = InstanceDispatchKey>,
587
1.82k
    ) -> Option<Arc<InstanceInfoWrapper<T>>> {
588
1.82k
        self.instance_map
589
1.82k
            .lock()
590
1.82k
            .unwrap()
591
1.82k
            .get()
592
1.82k
            .get(&instance.get_dispatch_key())
593
1.82k
            .map(Arc::clone)
594
1.82k
    }
595
596
27
    fn create_physical_device_infos<U: Borrow<vk::PhysicalDevice>>(
597
27
        &self,
598
27
        instance: vk::Instance,
599
27
        physical_devices: impl IntoIterator<Item = U>,
600
27
    ) {
601
54
        for 
physical_device27
in physical_devices {
602
27
            let mut physical_device_map = self.physical_device_map.lock().unwrap();
603
27
            let mut physical_device_map = physical_device_map.get_mut_or_default();
604
27
            if let Some(
physical_device_info2
) = physical_device_map.get(physical_device.borrow()) {
605
2
                assert_eq!(physical_device_info.owner_instance, instance);
606
2
                continue;
607
25
            }
608
25
            let instance_info = self.get_instance_info(instance).unwrap_or_else(|| {
609
0
                panic!("Unknown VkInstance handle: {:#018x}", instance.as_raw())
610
25
            });
611
25
            let properties = unsafe {
612
25
                instance_info
613
25
                    .dispatch_table
614
25
                    .core
615
25
                    .get_physical_device_properties(*physical_device.borrow())
616
25
            };
617
25
            physical_device_map.insert(
618
25
                *physical_device.borrow(),
619
25
                Arc::new(PhysicalDeviceInfoWrapper {
620
25
                    owner_instance: instance,
621
25
                    properties,
622
25
                }),
623
25
            );
624
25
        }
625
27
    }
626
627
5.22k
    fn get_device_info(
628
5.22k
        &self,
629
5.22k
        device: impl DispatchableObject<DispatchKey = DeviceDispatchKey>,
630
5.22k
    ) -> Option<Arc<DeviceInfoWrapper<T>>> {
631
5.22k
        self.device_map
632
5.22k
            .lock()
633
5.22k
            .unwrap()
634
5.22k
            .get()
635
5.22k
            .get(&device.get_dispatch_key())
636
5.22k
            .map(Arc::clone)
637
5.22k
    }
638
639
27
    fn get_physical_info(
640
27
        &self,
641
27
        physical_device: vk::PhysicalDevice,
642
27
    ) -> Option<Arc<PhysicalDeviceInfoWrapper>> {
643
27
        self.physical_device_map
644
27
            .lock()
645
27
            .unwrap()
646
27
            .get()
647
27
            .get(&physical_device)
648
27
            .map(Arc::clone)
649
27
    }
650
651
48
    extern "system" fn create_instance(
652
48
        create_info: *const vk::InstanceCreateInfo,
653
48
        allocator: *const vk::AllocationCallbacks,
654
48
        p_instance: *mut vk::Instance,
655
48
    ) -> vk::Result {
656
48
        let p_next_chain = unsafe { create_info.as_ref() }
657
48
            .map(|create_info| create_info.p_next as *mut vk::BaseOutStructure)
658
48
            .unwrap_or(null_mut());
659
48
        let mut p_next_chain: VulkanBaseOutStructChain = unsafe { p_next_chain.as_mut() }.into();
660
48
        let layer_create_info = p_next_chain.find_map(|out_struct| {
661
48
            let out_struct = out_struct as *mut vk::BaseOutStructure;
662
48
            let layer_create_info = unsafe {
663
48
                ash::match_out_struct!(match out_struct {
664
                    out_struct @ VkLayerInstanceCreateInfo => {
665
48
                        out_struct
666
                    }
667
                    _ => {
668
0
                        return None;
669
                    }
670
                })
671
            };
672
48
            if layer_create_info.function == VkLayerFunction::VK_LAYER_LINK_INFO {
673
48
                Some(layer_create_info)
674
            } else {
675
0
                None
676
            }
677
48
        });
678
48
        let layer_create_info = match layer_create_info {
679
48
            Some(layer_create_info) => layer_create_info,
680
            None => {
681
0
                error!("failed to find the VkLayerInstanceCreateInfo struct in the chain.");
682
0
                return vk::Result::ERROR_INITIALIZATION_FAILED;
683
            }
684
        };
685
48
        let layer_info = unsafe { layer_create_info.u.pLayerInfo.as_ref() }.unwrap();
686
48
        layer_create_info.u.pLayerInfo = layer_info.pNext;
687
48
688
48
        let get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr =
689
48
            layer_info.pfnNextGetInstanceProcAddr;
690
48
691
48
        let global = Self::instance();
692
48
        let hooked =
693
48
            T::GlobalHooksInfo::hooked_commands().contains(&LayerVulkanCommand::CreateInstance);
694
48
        let layer_result = if hooked {
695
3
            global.layer_info.global_hooks().create_instance(
696
3
                unsafe { create_info.as_ref() }.unwrap(),
697
3
                layer_info,
698
3
                unsafe { allocator.as_ref() },
699
3
                p_instance,
700
3
            )
701
        } else {
702
45
            LayerResult::Unhandled
703
        };
704
705
0
        match layer_result {
706
0
            LayerResult::Handled(Ok(())) => {}
707
0
            LayerResult::Handled(Err(e)) => return e,
708
            LayerResult::Unhandled => {
709
144
                let 
get_proc_addr48
= |name: &CStr| -> *const c_void {
710
144
                    let fp = unsafe { get_instance_proc_addr(vk::Instance::null(), name.as_ptr()) };
711
144
                    if let Some(
fp56
) = fp {
712
56
                        return fp as *const _;
713
88
                    }
714
88
                    std::ptr::null()
715
144
                };
716
48
                let entry = vk::EntryFnV1_0::load(get_proc_addr);
717
48
718
48
                let ret: vk::Result =
719
48
                    unsafe { (entry.create_instance)(create_info, allocator, p_instance) };
720
48
                if !
matches!0
(ret, vk::Result::SUCCESS) {
721
0
                    return ret;
722
48
                }
723
            }
724
        };
725
726
48
        let instance = *unsafe { p_instance.as_ref() }.unwrap();
727
48
        let ash_instance = unsafe {
728
48
            ash::Instance::load(
729
48
                &ash::vk::StaticFn {
730
48
                    get_instance_proc_addr,
731
48
                },
732
48
                instance,
733
48
            )
734
48
        };
735
48
736
48
        let create_info = unsafe { create_info.as_ref() }.unwrap();
737
48
        let enabled_extensions = unsafe {
738
48
            slice_from_raw_parts(
739
48
                create_info.pp_enabled_extension_names,
740
48
                create_info.enabled_extension_count,
741
48
            )
742
48
        };
743
48
        let enabled_extensions = unsafe { slice_to_owned_strings(enabled_extensions) }
744
48
            .filter_map(|extension_name| 
match extension_name.as_str().try_into()8
{
745
8
                Ok(extension) => Some(extension),
746
0
                Err(e) => {
747
0
                    warn!(
748
0
                        "Failed to recognize the extension {}: {}",
749
                        extension_name, e
750
                    );
751
0
                    None
752
                }
753
48
            
}8
)
754
48
            .collect();
755
48
        let api_version = unsafe { create_info.p_application_info.as_ref() }
756
48
            .map(|app_info| 
app_info.api_version8
)
757
48
            .unwrap_or(0);
758
48
        let api_version = if api_version == 0 {
759
42
            ApiVersion { major: 1, minor: 0 }
760
        } else {
761
6
            api_version.into()
762
        };
763
48
        let ash_instance = Arc::new(ash_instance);
764
48
        let customized_info = global.layer_info.create_instance_info(
765
48
            create_info,
766
48
            unsafe { allocator.as_ref() },
767
48
            Arc::clone(&ash_instance),
768
48
            get_instance_proc_addr,
769
48
        );
770
48
        let is_create_device_hooked = global
771
48
            .layer_info
772
48
            .hooked_instance_commands(customized_info.borrow())
773
48
            .any(|command| 
command == LayerVulkanCommand::CreateDevice8
);
774
48
        let instance_commands = global.create_instance_commands(customized_info.borrow());
775
48
        let device_commands = global.create_device_commands(customized_info.borrow(), None);
776
48
        {
777
48
            let key = instance.get_dispatch_key();
778
48
            let mut instance_map = global.instance_map.lock().unwrap();
779
48
            let mut instance_map = instance_map.get_mut_or_default();
780
48
            if instance_map.contains_key(&key) {
781
0
                error!(
782
0
                    "duplicate instances: instance {:?} already exists",
783
                    instance
784
                );
785
0
                return vk::Result::ERROR_INITIALIZATION_FAILED;
786
48
            }
787
48
            instance_map.insert(
788
48
                key,
789
48
                Arc::new(InstanceInfoWrapper {
790
48
                    get_instance_proc_addr,
791
48
                    dispatch_table: InstanceDispatchTable::load(
792
48
                        get_instance_proc_addr,
793
48
                        ash_instance,
794
48
                    ),
795
48
                    api_version,
796
48
                    enabled_extensions,
797
48
                    instance_commands,
798
48
                    device_commands,
799
48
                    is_create_device_hooked,
800
48
                    customized_info,
801
48
                }),
802
48
            );
803
48
        }
804
48
        vk::Result::SUCCESS
805
48
    }
806
807
49
    extern "system" fn destroy_instance(
808
49
        instance: vk::Instance,
809
49
        allocator: *const vk::AllocationCallbacks,
810
49
    ) {
811
49
        if instance == vk::Instance::null() {
812
1
            return;
813
48
        }
814
48
        let dispatch_key = instance.get_dispatch_key();
815
48
        let global = Self::instance();
816
48
        let instance_info = global
817
48
            .instance_map
818
48
            .lock()
819
48
            .unwrap()
820
48
            .get_mut_or_default()
821
48
            .remove(&dispatch_key);
822
48
        let instance_info = instance_info.unwrap();
823
48
        let instance_info = match Arc::try_unwrap(instance_info) {
824
48
            Ok(instance_info) => instance_info,
825
0
            Err(_) => panic!(
826
0
                "This should be the sole instance dispatch table reference for instance {:?}.",
827
0
                instance
828
0
            ),
829
        };
830
48
        global
831
48
            .physical_device_map
832
48
            .lock()
833
48
            .unwrap()
834
48
            .get_mut_or_default()
835
48
            .retain(|_, physical_device_info| 
physical_device_info.owner_instance != instance25
);
836
48
        unsafe {
837
48
            (instance_info.dispatch_table.core.fp_v1_0().destroy_instance)(instance, allocator)
838
        };
839
49
    }
840
841
54
    extern "system" fn enumerate_physical_devices(
842
54
        instance: vk::Instance,
843
54
        p_physical_device_count: *mut u32,
844
54
        p_physical_devices: *mut vk::PhysicalDevice,
845
54
    ) -> vk::Result {
846
54
        let global = Self::instance();
847
54
        let ash_instance = &global
848
54
            .get_instance_info(instance)
849
54
            .expect("Must be a valid VkInstance")
850
54
            .dispatch_table
851
54
            .core;
852
54
        let res = unsafe {
853
54
            (ash_instance.fp_v1_0().enumerate_physical_devices)(
854
54
                instance,
855
54
                p_physical_device_count,
856
54
                p_physical_devices,
857
54
            )
858
54
        };
859
54
        if (res == vk::Result::SUCCESS || 
res == vk::Result::INCOMPLETE0
)
860
54
            && !p_physical_devices.is_null()
861
27
        {
862
27
            let physical_device_count = unsafe { p_physical_device_count.as_ref() }.unwrap();
863
27
            let physical_devices =
864
27
                unsafe { slice_from_raw_parts(p_physical_devices, *physical_device_count) };
865
27
            global.create_physical_device_infos(instance, physical_devices);
866
27
        }
867
54
        res
868
54
    }
869
870
0
    extern "system" fn enumerate_physical_device_groups(
871
0
        instance: vk::Instance,
872
0
        p_physical_device_group_count: *mut u32,
873
0
        p_physical_device_group_properties: *mut vk::PhysicalDeviceGroupProperties,
874
0
    ) -> vk::Result {
875
0
        let global = Self::instance();
876
0
        let ash_instance = &global
877
0
            .get_instance_info(instance)
878
0
            .expect("Must be a valid VkInstance")
879
0
            .dispatch_table
880
0
            .core;
881
0
        let res = unsafe {
882
0
            (ash_instance.fp_v1_1().enumerate_physical_device_groups)(
883
0
                instance,
884
0
                p_physical_device_group_count,
885
0
                p_physical_device_group_properties,
886
0
            )
887
0
        };
888
0
        if (res == vk::Result::SUCCESS || res == vk::Result::INCOMPLETE)
889
0
            && !p_physical_device_group_count.is_null()
890
0
        {
891
0
            let physical_device_group_count =
892
0
                *unsafe { p_physical_device_group_count.as_ref() }.unwrap();
893
0
            let physical_device_groups = unsafe {
894
0
                slice_from_raw_parts(
895
0
                    p_physical_device_group_properties,
896
0
                    physical_device_group_count,
897
0
                )
898
0
            };
899
0
            let physical_devices =
900
0
                physical_device_groups
901
0
                    .iter()
902
0
                    .flat_map(|physical_device_group| {
903
0
                        &physical_device_group.physical_devices[..physical_device_group
904
0
                            .physical_device_count
905
0
                            .try_into()
906
0
                            .unwrap()]
907
0
                    });
908
0
            global.create_physical_device_infos(instance, physical_devices);
909
0
        }
910
0
        res
911
0
    }
912
913
25
    extern "system" fn create_device(
914
25
        physical_device: vk::PhysicalDevice,
915
25
        create_info: *const vk::DeviceCreateInfo,
916
25
        p_allocator: *const vk::AllocationCallbacks,
917
25
        p_device: *mut vk::Device,
918
25
    ) -> vk::Result {
919
25
        let create_info = unsafe { create_info.as_ref() }.unwrap();
920
25
        let mut p_next_chain: VulkanBaseOutStructChain =
921
25
            unsafe { (create_info.p_next as *mut vk::BaseOutStructure).as_mut() }.into();
922
25
        let layer_create_info = p_next_chain.find_map(|out_struct| {
923
25
            let out_struct = out_struct as *mut vk::BaseOutStructure;
924
25
            let layer_create_info = unsafe {
925
25
                ash::match_out_struct!(match out_struct {
926
                    out_struct @ VkLayerDeviceCreateInfo => {
927
25
                        out_struct
928
                    }
929
                    _ => {
930
0
                        return None;
931
                    }
932
                })
933
            };
934
25
            if layer_create_info.function == VkLayerFunction::VK_LAYER_LINK_INFO {
935
25
                Some(layer_create_info)
936
            } else {
937
0
                None
938
            }
939
25
        });
940
25
        let layer_create_info = match layer_create_info {
941
25
            Some(layer_create_info) => layer_create_info,
942
            None => {
943
0
                error!("failed to find the VkLayerDeviceCreateInfo struct in the chain.");
944
0
                return vk::Result::ERROR_INITIALIZATION_FAILED;
945
            }
946
        };
947
25
        let layer_link = unsafe { layer_create_info.u.pLayerInfo.as_ref() }.unwrap();
948
25
        layer_create_info.u.pLayerInfo = layer_link.pNext;
949
25
950
25
        let get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr =
951
25
            layer_link.pfnNextGetInstanceProcAddr;
952
25
        let get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr = layer_link.pfnNextGetDeviceProcAddr;
953
25
954
25
        let global = Self::instance();
955
25
        let physical_device_info = global
956
25
            .get_physical_info(physical_device)
957
25
            .expect("physical device must be a valid VkPhysicalDevice.");
958
25
        let instance_info = global
959
25
            .get_instance_info(physical_device_info.owner_instance)
960
25
            .expect("The owner instance of this physical device must be registered.");
961
25
962
25
        let create_device_name = CString::new("vkCreateDevice").unwrap();
963
25
        let next_create_device = unsafe {
964
25
            get_instance_proc_addr(
965
25
                instance_info.dispatch_table.core.handle(),
966
25
                create_device_name.as_ptr(),
967
25
            )
968
25
        };
969
25
        let next_create_device: vk::PFN_vkCreateDevice =
970
25
            unsafe { std::mem::transmute(next_create_device) };
971
25
        let mut create_info = *create_info;
972
25
        let requested_extensions = unsafe {
973
25
            slice_from_raw_parts(
974
25
                create_info.pp_enabled_extension_names,
975
25
                create_info.enabled_extension_count,
976
25
            )
977
25
        };
978
25
        let requested_extensions =
979
25
            unsafe { slice_to_owned_strings(requested_extensions) }.collect::<Vec<_>>();
980
25
        let create_device_res = if instance_info.is_create_device_hooked {
981
4
            instance_info
982
4
                .customized_info
983
4
                .borrow()
984
4
                .hooks()
985
4
                .create_device(
986
4
                    physical_device,
987
4
                    &create_info,
988
4
                    layer_link,
989
4
                    unsafe { p_allocator.as_ref() },
990
4
                    unsafe { ptr_as_uninit_mut(p_device) }.unwrap(),
991
4
                )
992
        } else {
993
21
            LayerResult::Unhandled
994
        };
995
25
        let layer_manifest = T::manifest();
996
0
        match create_device_res {
997
0
            LayerResult::Handled(Ok(())) => {}
998
0
            LayerResult::Handled(Err(e)) => return e,
999
            LayerResult::Unhandled => {
1000
25
                let enabled_extensions = requested_extensions
1001
25
                    .iter()
1002
25
                    .filter_map(|extension_name| {
1003
12
                        let extension_name_cstring = CString::new(extension_name.clone())
1004
12
                            .unwrap_or_else(|e| {
1005
0
                                panic!("Failed to create CString from {}: {}", extension_name, e)
1006
12
                            });
1007
12
                        let 
extension: Extension11
= match extension_name.as_str().try_into() {
1008
11
                            Ok(extension) => extension,
1009
1
                            Err(_) => return Some(extension_name_cstring),
1010
                        };
1011
11
                        if layer_manifest
1012
11
                            .device_extensions
1013
11
                            .iter()
1014
11
                            .any(|layer_extension| 
layer_extension.name == extension9
)
1015
                        {
1016
7
                            None
1017
                        } else {
1018
4
                            Some(extension_name_cstring)
1019
                        }
1020
25
                    
}12
)
1021
25
                    .collect::<Vec<_>>();
1022
25
                let enabled_extensions = enabled_extensions
1023
25
                    .iter()
1024
25
                    .map(|extension_name| 
extension_name.as_ptr()5
)
1025
25
                    .collect::<Vec<_>>();
1026
25
                create_info.enabled_extension_count = enabled_extensions.len().try_into().unwrap();
1027
25
                create_info.pp_enabled_extension_names = if enabled_extensions.is_empty() {
1028
20
                    null()
1029
                } else {
1030
5
                    enabled_extensions.as_ptr()
1031
                };
1032
25
                let res = unsafe {
1033
25
                    next_create_device(physical_device, &create_info, p_allocator, p_device)
1034
25
                };
1035
25
                if res != vk::Result::SUCCESS {
1036
2
                    return res;
1037
23
                }
1038
            }
1039
        }
1040
1041
23
        let device = *unsafe { p_device.as_ref() }.unwrap();
1042
23
        let ash_instance = Arc::clone(&instance_info.dispatch_table.core);
1043
23
        let ash_device = unsafe {
1044
23
            // ash will also try to load instance-level dispatchable commands with
1045
23
            // vkGetDeviceProcAddr. Although that won't end up with undefined behavior, and we
1046
23
            // should always expect NULL returned according to the spec, we may see Android vulkan
1047
23
            // loader complaining about internal vkGetDeviceProcAddr called for <function name>,
1048
23
            // which should be benign.
1049
23
            ash::Device::load(
1050
23
                &vk::InstanceFnV1_0 {
1051
23
                    get_device_proc_addr,
1052
23
                    ..ash_instance.fp_v1_0().clone()
1053
23
                },
1054
23
                device,
1055
23
            )
1056
23
        };
1057
23
        let ash_device = Arc::new(ash_device);
1058
23
        let enabled_extensions = requested_extensions
1059
23
            .iter()
1060
23
            .filter_map(|name| {
1061
9
                let extension_name: Option<Extension> = name.as_str().try_into().ok();
1062
9
                extension_name
1063
23
            })
1064
23
            .collect::<BTreeSet<_>>();
1065
23
        let api_version = instance_info
1066
23
            .api_version
1067
23
            .min(physical_device_info.properties.api_version.into());
1068
23
        let customized_info = global.layer_info.create_device_info(
1069
23
            physical_device,
1070
23
            &create_info,
1071
23
            unsafe { p_allocator.as_ref() },
1072
23
            Arc::clone(&ash_device),
1073
23
            get_device_proc_addr,
1074
23
        );
1075
23
        let device_commands = global.create_device_commands(
1076
23
            instance_info.customized_info.borrow(),
1077
23
            Some(customized_info.borrow()),
1078
23
        );
1079
23
        {
1080
23
            let mut device_map = global.device_map.lock().unwrap();
1081
23
            let mut device_map = device_map.get_mut_or_default();
1082
23
            assert!(
1083
23
                !device_map.contains_key(&device.get_dispatch_key()),
1084
0
                "duplicate VkDevice: {:?}",
1085
                device
1086
            );
1087
23
            device_map.insert(
1088
23
                device.get_dispatch_key(),
1089
23
                Arc::new(DeviceInfoWrapper {
1090
23
                    dispatch_table: DeviceDispatchTable::load(get_device_proc_addr, ash_device),
1091
23
                    get_device_proc_addr,
1092
23
                    api_version,
1093
23
                    enabled_extensions,
1094
23
                    device_commands,
1095
23
                    customized_info,
1096
23
                }),
1097
23
            );
1098
23
        }
1099
23
        vk::Result::SUCCESS
1100
25
    }
1101
1102
24
    extern "system" fn destroy_device(
1103
24
        device: vk::Device,
1104
24
        p_allocator: *const vk::AllocationCallbacks,
1105
24
    ) {
1106
24
        if device == vk::Device::null() {
1107
1
            return;
1108
23
        }
1109
23
        let global = Self::instance();
1110
23
        let device_info = match Arc::try_unwrap(
1111
23
            global
1112
23
                .device_map
1113
23
                .lock()
1114
23
                .unwrap()
1115
23
                .get_mut_or_default()
1116
23
                .remove(&device.get_dispatch_key())
1117
23
                .expect("device must be registered"),
1118
23
        ) {
1119
23
            Ok(device_info) => device_info,
1120
0
            Err(_) => panic!("This should be the sole owner of the device {:?}", device),
1121
        };
1122
23
        let allocation_callback = unsafe { p_allocator.as_ref() };
1123
23
        unsafe {
1124
23
            device_info
1125
23
                .dispatch_table
1126
23
                .core
1127
23
                .destroy_device(allocation_callback)
1128
        };
1129
24
    }
1130
1131
4
    fn layer_properties() -> Vec<vk::LayerProperties> {
1132
4
        let layer_manifest = T::manifest();
1133
4
        // layer_name and description will be set later
1134
4
        let mut layer_property: vk::LayerProperties = vk::LayerProperties::builder()
1135
4
            .spec_version(layer_manifest.spec_version)
1136
4
            .implementation_version(layer_manifest.implementation_version)
1137
4
            .build();
1138
4
        assert!(layer_manifest.name.len() < vk::MAX_EXTENSION_NAME_SIZE);
1139
4
        let layer_name = CString::new(layer_manifest.name).unwrap();
1140
4
        let layer_name = cast_slice(layer_name.as_bytes());
1141
4
        layer_property.layer_name[..layer_name.len()].copy_from_slice(layer_name);
1142
4
1143
4
        let layer_description = CString::new(layer_manifest.description).unwrap();
1144
4
        let layer_description = cast_slice(layer_description.as_bytes());
1145
4
        assert!(layer_description.len() < vk::MAX_DESCRIPTION_SIZE);
1146
4
        layer_property.description[..layer_description.len()].copy_from_slice(layer_description);
1147
4
        vec![layer_property]
1148
4
    }
1149
1150
    // Introspection queries required by Android, so we need to expose them as public functions so
1151
    // that the user can further expose them as functions exported by the dynamic link library.
1152
1153
    /// The `vkEnumerateInstanceLayerProperties` entry point provided by the layer framework.
1154
    ///
1155
    /// The return value is decided by [`Layer::manifest`]. Only enumerate the layer itself
1156
    /// according to the
1157
    /// [layer rule](<https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderLayerInterface.md#:~:text=vkEnumerateInstanceLayerProperties%20must%20enumerate%20and%20only%20enumerate%20the%20layer%20itself.>).
1158
    ///
1159
    /// # Safety
1160
    /// See valid usage of `vkEnumerateInstanceLayerProperties` at
1161
    /// <https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceLayerProperties.html>.
1162
    #[deny(unsafe_op_in_unsafe_fn)]
1163
4
    pub unsafe extern "system" fn enumerate_instance_layer_properties(
1164
4
        property_count: *mut u32,
1165
4
        properties: *mut vk::LayerProperties,
1166
4
    ) -> vk::Result {
1167
4
        let ret_properties = Self::layer_properties();
1168
4
        // Safe, because the caller guarantees that `property_count` is a valid pointer to u32, and
1169
4
        // if the value referenced by property_count is not 0, and properties is not NULL,
1170
4
        // properties must be a valid pointer to an array of property_count vk::LayerProperties
1171
4
        // structures. See details in
1172
4
        // VUID-vkEnumerateInstanceLayerProperties-pPropertyCount-parameter and
1173
4
        // VUID-vkEnumerateInstanceLayerProperties-pProperties-parameter.
1174
4
        unsafe {
1175
4
            fill_vk_out_array(
1176
4
                &ret_properties,
1177
4
                NonNull::new(property_count).unwrap(),
1178
4
                properties,
1179
4
            )
1180
4
        }
1181
4
    }
1182
1183
    /// The `vkEnumerateInstanceExtensionProperties` entry point provided by the layer framework.
1184
    ///
1185
    /// Returns an empty list with `VK_SUCCESS` if the layer name matches; returns
1186
    /// `VK_ERROR_LAYER_NOT_PRESENT` with all the out pointers untouched, according to the
1187
    /// [`LLP_LAYER_15`](<https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderLayerInterface.md#:~:text=LLP_LAYER_15,Conventions%20and%20Rules>)
1188
    /// rule.
1189
    ///
1190
    /// # Safety
1191
    /// See valid usage of `vkEnumerateInstanceExtensionProperties` at
1192
    /// <https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkEnumerateInstanceExtensionProperties.html>.
1193
    #[deny(unsafe_op_in_unsafe_fn)]
1194
2
    pub unsafe extern "system" fn enumerate_instance_extension_properties(
1195
2
        layer_name: *const c_char,
1196
2
        property_count: *mut u32,
1197
2
        _: *mut vk::ExtensionProperties,
1198
2
    ) -> vk::Result {
1199
2
        if !layer_name.is_null() {
1200
2
            let layer_name = unsafe { CStr::from_ptr(layer_name) }
1201
2
                .to_str()
1202
2
                .expect(concat!(
1203
2
                    "According to \
1204
2
                     VUID-vkEnumerateInstanceExtensionProperties-pLayerName-parameter, ",
1205
2
                    "if p_layer_name is not NULL, p_layer_name must be a null-terminated UTF-8 \
1206
2
                     string."
1207
2
                ));
1208
2
            if layer_name == T::manifest().name {
1209
                // Safe, because the caller guarantees that if the passed in `property_count` is not
1210
                // null, it's a valid pointer to u32.
1211
2
                if let Some(property_count) = unsafe { property_count.as_mut() } {
1212
2
                    *property_count = 0;
1213
2
                
}0
1214
2
                return vk::Result::SUCCESS;
1215
0
            }
1216
0
        }
1217
0
        vk::Result::ERROR_LAYER_NOT_PRESENT
1218
2
    }
1219
1220
    /// The `vkEnumerateDeviceLayerProperties` entry point provided by the layer framework.
1221
    ///
1222
    /// The return value is decided by [`Layer::manifest`]. Only enumerate the layer itself
1223
    /// according to the
1224
    /// [layer interface version 0 requirement](<https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderLayerInterface.md#:~:text=vkEnumerateDeviceLayerProperties%20enumerates%20a,device%20function%20interception.>).
1225
    /// Note that although this function
1226
    /// [is deprecated](<https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderLayerInterface.md#:~:text=vkEnumerateDeviceLayerProperties%20is%20deprecated,in%20undefined%20behavior.>)
1227
    /// in the Khronos Vulkan loader, it is still used in the Android Vulkan loader.
1228
    ///
1229
    /// # Safety
1230
    /// See valid usage of `vkEnumerateDeviceLayerProperties` at
1231
    /// <https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkEnumerateDeviceLayerProperties.html>.
1232
    #[deny(unsafe_op_in_unsafe_fn)]
1233
0
    pub unsafe extern "system" fn enumerate_device_layer_properties(
1234
0
        _: vk::PhysicalDevice,
1235
0
        p_property_count: *mut u32,
1236
0
        p_properties: *mut vk::LayerProperties,
1237
0
    ) -> vk::Result {
1238
0
        // TODO: call into the customized instance data with the vk::PhysicalDevice to provide more
1239
0
        // flexibility.
1240
0
        let ret_properties = Self::layer_properties();
1241
0
        // Safe, because the caller guarantees that `p_property_count` is a valid pointer to u32,
1242
0
        // and if the value referenced by `p_property_count` is not 0, and `p_properties` is not
1243
0
        // NULL, `p_properties` must be a valid pointer to an array of `p_property_count`
1244
0
        // vk::LayerProperties structures. See details in
1245
0
        // VUID-vkEnumerateDeviceLayerProperties-pPropertyCount-parameter
1246
0
        // and VUID-vkEnumerateDeviceLayerProperties-pProperties-parameter.
1247
0
        unsafe {
1248
0
            fill_vk_out_array(
1249
0
                &ret_properties,
1250
0
                NonNull::new(p_property_count).expect(concat!(
1251
0
                    "p_property_count must be a valid pointer to u32 according to ",
1252
0
                    "VUID-vkEnumerateDeviceLayerProperties-pPropertyCount-parameter"
1253
0
                )),
1254
0
                p_properties,
1255
0
            )
1256
0
        }
1257
0
    }
1258
1259
    /// The `vkEnumerateDeviceExtensionProperties` entry point provided by the layer framework.
1260
    ///
1261
    /// The return value is decided by [`Layer::manifest`] where `p_layer_name` is itself. If the
1262
    /// `p_layer_name` doesn't match, the behavior depends on whether the `physical_device` argument
1263
    /// is `VK_NULL_HANDLE` or not: if `physical_device` argument is `VK_NULL_HANDLE`,
1264
    /// `VK_ERROR_LAYER_NOT_PRESENT` is returned; if `physical_device` is not `VK_NULL_HANDLE`, the
1265
    /// layer framework calls into the next layer of the call chain. This behavior is defined by the [layer interface version 0](<https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderLayerInterface.md#:~:text=vkEnumerateDeviceExtensionProperties%20enumerates%20device,function%20never%20fails.>)
1266
    /// and
1267
    /// [`LLP_LAYER_16`](<https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderLayerInterface.md#:~:text=LLP_LAYER_16,Conventions%20and%20Rules>).
1268
    ///
1269
    /// # Safety
1270
    /// See valid usage of `vkEnumerateDeviceExtensionProperties` at
1271
    /// <https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkEnumerateDeviceExtensionProperties.html>.
1272
    /// A NULL `VkPhysicalDevice` can also be used to call this interface, according to the
1273
    /// [layer interface version 0](<https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderLayerInterface.md#:~:text=vkEnumerateDeviceExtensionProperties%20enumerates%20device,function%20never%20fails.>).
1274
    #[deny(unsafe_op_in_unsafe_fn)]
1275
8
    pub unsafe extern "system" fn enumerate_device_extension_properties(
1276
8
        physical_device: vk::PhysicalDevice,
1277
8
        p_layer_name: *const c_char,
1278
8
        p_property_count: *mut u32,
1279
8
        p_properties: *mut vk::ExtensionProperties,
1280
8
    ) -> vk::Result {
1281
8
        let layer_manifest = T::manifest();
1282
8
        let is_this_layer = if p_layer_name.is_null() {
1283
3
            false
1284
        } else {
1285
5
            unsafe { CStr::from_ptr(p_layer_name) }
1286
5
                .to_str()
1287
5
                .map(|layer_name| layer_name == layer_manifest.name)
1288
5
                .unwrap_or(false)
1289
        };
1290
8
        if !is_this_layer {
1291
4
            if physical_device == vk::PhysicalDevice::null() {
1292
2
                return vk::Result::ERROR_LAYER_NOT_PRESENT;
1293
2
            }
1294
2
            let global = Self::instance();
1295
2
            let physical_device_info = global
1296
2
                .get_physical_info(physical_device)
1297
2
                .expect("physical device must be a valid VkPhysicalDevice.");
1298
2
            let instance_info = global
1299
2
                .get_instance_info(physical_device_info.owner_instance)
1300
2
                .expect("The owner instance of this physical device must be registered.");
1301
2
            return unsafe {
1302
2
                (instance_info
1303
2
                    .dispatch_table
1304
2
                    .core
1305
2
                    .fp_v1_0()
1306
2
                    .enumerate_device_extension_properties)(
1307
2
                    physical_device,
1308
2
                    p_layer_name,
1309
2
                    p_property_count,
1310
2
                    p_properties,
1311
2
                )
1312
            };
1313
4
        }
1314
4
        let property_count = NonNull::new(p_property_count).expect(concat!(
1315
4
            "`p_property_count` must be a valid pointer to u32 according to ",
1316
4
            "VUID-vkEnumerateDeviceExtensionProperties-pPropertyCount-parameter."
1317
4
        ));
1318
4
        // Safe because the caller guarantees `p_property_count` is a valid pointer to u32 according
1319
4
        // to VUID-vkEnumerateDeviceExtensionProperties-pPropertyCount-parameter, and if
1320
4
        // `p_property_count` doesn't point to 0, p_properties is either NULL or a valid pointer to
1321
4
        // an array of `p_property_count` `vk::ExtensionProperties` structures according to
1322
4
        // VUID-vkEnumerateDeviceExtensionProperties-pProperties-parameter.
1323
4
        let device_extensions = layer_manifest
1324
4
            .device_extensions
1325
4
            .iter()
1326
4
            .cloned()
1327
4
            .map(Into::<vk::ExtensionProperties>::into)
1328
4
            .collect::<Vec<_>>();
1329
4
        unsafe { fill_vk_out_array(&device_extensions, property_count, p_properties) }
1330
8
    }
1331
1332
    /// The `vkGetInstanceProcAddr` entry point provided by the layer framework.
1333
    ///
1334
    /// The layer framework will make use of [`Layer::hooked_instance_commands`] and
1335
    /// [`Layer::hooked_device_commands`] (with the `device_info` argument being [`None`]) to decide
1336
    /// whether a local function pointer should be returned or should just passthrough to the next
1337
    /// layer in the call chain. Note that the layer implementation doesn't have to take care of
1338
    /// whether the command is enabled/available, and only needs to use the interfaces to express
1339
    /// the intent. The layer framework should handle most of the logic(e.g. the requirement of
1340
    /// [`LLP_LAYER_18`](<https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderLayerInterface.md#pre-instance-functions:~:text=LLP_LAYER_18,Conventions%20and%20Rules>))
1341
    /// here unless the layer implementation decides to intercept `vkGetInstanceProcAddr`.
1342
    ///
1343
    /// The actual behavior is defined as follow:
1344
    ///
1345
    /// 1. If the `instance` parameter is `VK_NULL_HANDLE`, returns the local function pointers of
1346
    ///    the current layer for all
1347
    ///    [global commands](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#:~:text=The%20global%20commands%20are%3A%20vkEnumerateInstanceVersion%2C%20vkEnumerateInstanceExtensionProperties%2C%20vkEnumerateInstanceLayerProperties%2C%20and%20vkCreateInstance.)
1348
    ///    and `vkGetInstanceProcAddr`; `NULL` is returned for other Vulkan commands. One culprit
1349
    ///    for now is that currently the layer framework always returns `NULL` for
1350
    ///    `vkEnumerateInstanceVersion`, but that should be Ok, because the layer framework
1351
    ///    currently doesn't allow to intercept pre-instance functions anyway, so this function
1352
    ///    should be completely handled by the Vulkan loader.
1353
    ///
1354
    /// 1. If instance is not null, the situation is more complicated:
1355
    ///
1356
    ///    If the layer implementation intercepts the `vkGetInstanceProcAddr` function(i.e.
1357
    ///    [`Layer::hooked_instance_commands`] returns `vkGetInstanceProcAddr`), the layer framework
1358
    ///    just calls [`InstanceHooks::get_instance_proc_addr`] and return the return value if
1359
    ///    [`LayerResult::Handled`] is returned.
1360
    ///
1361
    ///    Otherwise, the layer framework handles most of the logic according to
1362
    ///    [`Layer::hooked_instance_commands`] and [`Layer::hooked_device_commands`]:
1363
    ///
1364
    ///     1. For dispatchable commands that are introspection queries:
1365
    ///        `vkEnumerateDeviceExtensionProperties`, `vkEnumerateDeviceLayerProperties`, always
1366
    ///        returns a local function pointer of the current layer.
1367
    ///
1368
    ///     1. For `vkDestroyInstance`, `vkCreateDevice`, `vkDestroyDevice`, always returns a local
1369
    ///        function pointer. The layer framework needs to intercept those functions to build the
1370
    ///        dispatch table and perform instance/device specific initialization. Note that
1371
    ///        `vkCreateInstance` is a
1372
    ///        [global command](<https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#:~:text=The%20global%20commands%20are%3A%20vkEnumerateInstanceVersion%2C%20vkEnumerateInstanceExtensionProperties%2C%20vkEnumerateInstanceLayerProperties%2C%20and%20vkCreateInstance.>),
1373
    ///        so `NULL` will be returned if the `instance` argument is not `VK_NULL_HANDLE`.
1374
    ///
1375
    ///     1. For `vkEnumeratePhysicalDevices`, `vkEnumeratePhysicalDeviceGroups`, always returns a
1376
    ///        local function pointer. The layer framework needs to intercept those functions to
1377
    ///        build a map between `VkPhysicalDevice` and `VkInstance` so that the layer framework
1378
    ///        can find the correspondent `VkInstance` in `vkCreateDevice`.
1379
    ///
1380
    ///     1. For other core dispatchable commands and enabled instance extension dispatchable
1381
    ///        commands, if the layer implementation decides to intercept(according to
1382
    ///        [`Layer::hooked_instance_commands`] and [`Layer::hooked_device_commands`]), returns a
1383
    ///        local function pointer, otherwise returns the function pointer from the next layer.
1384
    ///
1385
    ///     1. For disabled instance extension dispatchable commands(either because the API version
1386
    ///        is not high enough or the extension is not enabled), directly call to the next layer
1387
    ///        regardless of whether the layer implementation wants to intercept the command or not,
1388
    ///        and rely on the next layer to return `NULL`.
1389
    ///
1390
    ///     1. For device extension dispatchable commands directly supported by the layer
1391
    ///        implementation according to [`LayerManifest::device_extensions`], always returns a
1392
    ///        local function pointer if the layer implementation intercepts the command. Otherwise,
1393
    ///        returns the function pointer of the next layer.
1394
    ///
1395
    ///     1. For device extension dispatchable commands not directly supported by the layer(i.e.
1396
    ///        the extension doesn't appear in the [`LayerManifest::device_extensions`] of the
1397
    ///        current layer):
1398
    ///
1399
    ///        * If the next layer returns `NULL`, `NULL` is always returned regardless of whether
1400
    ///          the layer implementation wants to intercept the command. This indicates that this
1401
    ///          device extension dispathcable command is not available for the instance.
1402
    ///
1403
    ///        * if the next layer returns non-NULL, a local function pointer is returned if the
1404
    ///          layer implementation wants to intercept the command, otherwise returns the function
1405
    ///          pointer of the next layer This indicates that this device extension dispathcable
1406
    ///          command is available for the instance.
1407
    ///
1408
    ///     1. Passthrough to the next layer if the command is not recognized.
1409
    ///
1410
    /// # Safety
1411
    /// See valid usage of `vkGetInstanceProcAddr` at
1412
    /// <https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html>.
1413
    #[deny(unsafe_op_in_unsafe_fn)]
1414
2.12k
    pub unsafe extern "system" fn get_instance_proc_addr(
1415
2.12k
        instance: vk::Instance,
1416
2.12k
        p_name: *const c_char,
1417
2.12k
    ) -> vk::PFN_vkVoidFunction {
1418
2.12k
        // Make sure Global is initialized.
1419
2.12k
        let global = Self::instance();
1420
2.12k
        // Safe because the caller is expected to pass in a C string in the name parameter. See
1421
2.12k
        // VUID-vkGetInstanceProcAddr-pName-parameter.
1422
2.12k
        let name = unsafe { CStr::from_ptr(p_name) };
1423
2.12k
        let name = name.to_str().expect(concat!(
1424
2.12k
            "According to VUID-vkGetInstanceProcAddr-pName-parameter, p_name must be a null-",
1425
2.12k
            "terminated UTF-8 string."
1426
2.12k
        ));
1427
2.12k
        // Returns a valid function pointer for global commands all the time, although this behavior
1428
2.12k
        // doesn't match the spec. See https://github.com/KhronosGroup/Vulkan-Loader/issues/1537 for
1429
2.12k
        // details.
1430
2.12k
        match name {
1431
2.12k
            "vkGetInstanceProcAddr" => {
1432
                return unsafe {
1433
4
                    std::mem::transmute::<vk::PFN_vkGetInstanceProcAddr, vk::PFN_vkVoidFunction>(
1434
4
                        Self::get_instance_proc_addr,
1435
4
                    )
1436
                }
1437
            }
1438
2.11k
            "vkEnumerateInstanceExtensionProperties" => {
1439
                return unsafe {
1440
99
                    std::mem::transmute::<
1441
99
                        vk::PFN_vkEnumerateInstanceExtensionProperties,
1442
99
                        vk::PFN_vkVoidFunction,
1443
99
                    >(Self::enumerate_instance_extension_properties)
1444
                }
1445
            }
1446
2.02k
            "vkEnumerateInstanceLayerProperties" => {
1447
                return unsafe {
1448
99
                    std::mem::transmute::<
1449
99
                        vk::PFN_vkEnumerateInstanceLayerProperties,
1450
99
                        vk::PFN_vkVoidFunction,
1451
99
                    >(Self::enumerate_instance_layer_properties)
1452
                }
1453
            }
1454
1.92k
            "vkCreateInstance" => {
1455
                return unsafe {
1456
102
                    std::mem::transmute::<vk::PFN_vkCreateInstance, vk::PFN_vkVoidFunction>(
1457
102
                        Self::create_instance,
1458
102
                    )
1459
                }
1460
            }
1461
1.81k
            _ => {}
1462
1.81k
        }
1463
1.81k
        if instance == vk::Instance::null() {
1464
            // TODO: allow inteception of vkEnumerateInstanceVersion and handle
1465
            // vkEnumerateInstanceVersion properly. For now, we still return NULL for
1466
            // vkEnumerateInstanceVersion. The Vulkan loader should cover us for this case.
1467
            // Per spec, if instance is NULL, and pName is neither NULL nor a global command, NULL
1468
            // should be returned.
1469
99
            return None;
1470
1.72k
        }
1471
1.72k
        let instance_info = global.get_instance_info(instance)
?0
;
1472
1.72k
        if global.get_instance_addr_proc_hooked {
1473
0
            if let LayerResult::Handled(res) = instance_info
1474
0
                .customized_info
1475
0
                .borrow()
1476
0
                .hooks()
1477
0
                .get_instance_proc_addr(name)
1478
            {
1479
0
                return res;
1480
0
            }
1481
1.72k
        }
1482
1.72k
        let get_next_proc_addr =
1483
1.46k
            || unsafe { (instance_info.get_instance_proc_addr)(instance, p_name) };
1484
1.72k
        let instance_commands = &instance_info.instance_commands;
1485
1.72k
        let instance_command = match instance_commands
1486
13.7k
            .binary_search_by_key(&name, |VulkanCommand { name, .. }| name
)1.72k
1487
        {
1488
1.50k
            Ok(index) => Some(&instance_commands[index]),
1489
215
            Err(_) => None,
1490
        };
1491
1.72k
        if let Some(
instance_command1.50k
) = instance_command {
1492
1.50k
            if !instance_command.hooked {
1493
1.19k
                return get_next_proc_addr();
1494
307
            }
1495
307
            let enabled = instance_command.features.is_command_enabled(
1496
307
                &instance_info.api_version,
1497
307
                &instance_info.enabled_extensions,
1498
307
            );
1499
307
            if !enabled {
1500
50
                return get_next_proc_addr();
1501
257
            }
1502
257
            return instance_command.proc;
1503
215
        }
1504
215
        let device_commands = &instance_info.device_commands;
1505
215
        let device_command =
1506
2.36k
            match 
device_commands.binary_search_by_key(&name, 215
|VulkanCommand { name, .. }| name
)215
{
1507
214
                Ok(index) => Some(&device_commands[index]),
1508
1
                Err(_) => None,
1509
            };
1510
215
        if let Some(
device_command214
) = device_command {
1511
214
            let next_proc_addr = get_next_proc_addr();
1512
214
            if !device_command.hooked {
1513
153
                return next_proc_addr;
1514
61
            }
1515
61
            let layer_device_extensions: BTreeSet<Extension> = T::manifest()
1516
61
                .device_extensions
1517
61
                .iter()
1518
61
                .map(|ExtensionProperties { name, .. }| 
name.clone()10
)
1519
61
                .collect();
1520
            // If the layer supports the command or the next proc addr can find it, this is an
1521
            // available device command.
1522
61
            let command_available = device_command
1523
61
                .features
1524
61
                .is_command_enabled(&instance_info.api_version, &layer_device_extensions)
1525
4
                || next_proc_addr.is_some();
1526
61
            if command_available {
1527
59
                return device_command.proc;
1528
            } else {
1529
2
                return next_proc_addr;
1530
            }
1531
1
        }
1532
1
        // We don't recognize this command.
1533
1
        get_next_proc_addr()
1534
2.12k
    }
1535
1536
    /// The `vkGetDeviceProcAddr` entry point provided by the layer framework.
1537
    ///
1538
    /// The layer framework will make use of [`Layer::hooked_device_commands`] to decide whether a
1539
    /// local function pointer should be returned or should passthrough to the next layer in the
1540
    /// call chain. Note that the layer implementation doesn't have to take care of whether the
1541
    /// command is enabled(either included in the requested core version or enabled extension), and
1542
    /// only needs to use the [`Layer::hooked_device_commands`] interface to express the intent. The
1543
    /// layer framework should handle most of the logic(e.g. the requirement of
1544
    /// [`LLP_LAYER_18`](<https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderLayerInterface.md#pre-instance-functions:~:text=LLP_LAYER_18,Conventions%20and%20Rules>))
1545
    /// here unless the layer implementation decides to intercept `vkGetDeviceProcAddr`.
1546
    ///
1547
    /// # Safety
1548
    /// See valid usage of `vkGetDeviceProcAddr` at
1549
    /// <https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetDeviceProcAddr.html>.
1550
    #[deny(unsafe_op_in_unsafe_fn)]
1551
5.22k
    pub unsafe extern "system" fn get_device_proc_addr(
1552
5.22k
        device: vk::Device,
1553
5.22k
        p_name: *const c_char,
1554
5.22k
    ) -> vk::PFN_vkVoidFunction {
1555
5.22k
        let name = unsafe { CStr::from_ptr(p_name) };
1556
5.22k
        let name = name.to_str().expect("name should be a valid UTF-8 string.");
1557
5.22k
        let global = Self::instance();
1558
5.22k
        let device_info = global.get_device_info(device)
?0
;
1559
5.22k
        if let LayerResult::Handled(
res0
) = device_info
1560
5.22k
            .customized_info
1561
5.22k
            .borrow()
1562
5.22k
            .hooks()
1563
5.22k
            .get_device_proc_addr(name)
1564
        {
1565
0
            return res;
1566
5.22k
        }
1567
5.22k
        let get_next_device_proc_addr =
1568
5.19k
            || unsafe { (device_info.get_device_proc_addr)(device, p_name) };
1569
5.22k
        let device_commands = &device_info.device_commands;
1570
5.17k
        let command = if let Ok(index) =
1571
57.4k
            
device_commands.binary_search_by_key(&name, 5.22k
|VulkanCommand { name, .. }| name
)5.22k
1572
        {
1573
5.17k
            &device_commands[index]
1574
        } else {
1575
43
            return get_next_device_proc_addr();
1576
        };
1577
5.17k
        if !command
1578
5.17k
            .features
1579
5.17k
            .is_command_enabled(&device_info.api_version, &device_info.enabled_extensions)
1580
        {
1581
2.12k
            return get_next_device_proc_addr();
1582
3.04k
        }
1583
3.04k
        if !command.hooked {
1584
3.01k
            return get_next_device_proc_addr();
1585
29
        }
1586
29
        command.proc
1587
5.22k
    }
1588
}
1589
1590
impl<T: Layer> Default for Global<T> {
1591
61
    fn default() -> Self {
1592
61
        let layer_info: T = Default::default();
1593
61
        let get_instance_addr_proc_hooked = T::GlobalHooksInfo::hooked_commands()
1594
61
            .contains(&LayerVulkanCommand::GetInstanceProcAddr);
1595
61
        Self {
1596
61
            instance_map: Default::default(),
1597
61
            physical_device_map: Default::default(),
1598
61
            device_map: Default::default(),
1599
61
            layer_info,
1600
61
            get_instance_addr_proc_hooked,
1601
61
        }
1602
61
    }
1603
}
1604
1605
/// A stub struct that intercept no commands, which implements [`GlobalHooks`] and
1606
/// [`GlobalHooksInfo`].
1607
#[derive(Default)]
1608
pub struct StubGlobalHooks;
1609
1610
8
#[auto_globalhooksinfo_impl]
1611
impl GlobalHooks for StubGlobalHooks {}
1612
1613
/// A stub struct that intercept no commands, which implements [`InstanceHooks`] and
1614
/// [`InstanceInfo`].
1615
#[derive(Default)]
1616
pub struct StubInstanceInfo;
1617
1618
5
#[auto_instanceinfo_impl]
1619
impl InstanceHooks for StubInstanceInfo {}
1620
1621
/// A stub struct that intercept no commands, which implements [`DeviceHooks`] and [`DeviceInfo`].
1622
#[derive(Default)]
1623
pub struct StubDeviceInfo;
1624
1625
189
#[auto_deviceinfo_impl]
1626
impl DeviceHooks for StubDeviceInfo {}
1627
1628
#[cfg(test)]
1629
mod tests {
1630
    use once_cell::sync::Lazy;
1631
1632
    use crate::test_utils::LayerManifestExt;
1633
    use std::{cmp::Ordering, mem::MaybeUninit};
1634
1635
    use super::*;
1636
1637
    #[test]
1638
1
    fn commands_must_be_sorted() {
1639
        #[derive(Default)]
1640
        struct TestLayer(StubGlobalHooks);
1641
1642
        impl Layer for TestLayer {
1643
            type GlobalHooksInfo = StubGlobalHooks;
1644
            type InstanceInfo = StubInstanceInfo;
1645
            type DeviceInfo = StubDeviceInfo;
1646
            type InstanceInfoContainer = StubInstanceInfo;
1647
            type DeviceInfoContainer = StubDeviceInfo;
1648
1649
2
            fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static {
1650
2
                &*GLOBAL
1651
2
            }
1652
1653
0
            fn manifest() -> LayerManifest {
1654
0
                LayerManifest::test_default()
1655
0
            }
1656
1657
0
            fn global_hooks_info(&self) -> &Self::GlobalHooksInfo {
1658
0
                &self.0
1659
0
            }
1660
1661
0
            fn create_instance_info(
1662
0
                &self,
1663
0
                _: &vk::InstanceCreateInfo,
1664
0
                _: Option<&vk::AllocationCallbacks>,
1665
0
                _: Arc<ash::Instance>,
1666
0
                _next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
1667
0
            ) -> Self::InstanceInfoContainer {
1668
0
                Default::default()
1669
0
            }
1670
1671
0
            fn create_device_info(
1672
0
                &self,
1673
0
                _: vk::PhysicalDevice,
1674
0
                _: &vk::DeviceCreateInfo,
1675
0
                _: Option<&vk::AllocationCallbacks>,
1676
0
                _: Arc<ash::Device>,
1677
0
                _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
1678
0
            ) -> Self::DeviceInfoContainer {
1679
0
                Default::default()
1680
0
            }
1681
        }
1682
1683
        static GLOBAL: Lazy<Global<TestLayer>> = Lazy::new(Default::default);
1684
1685
        #[inline]
1686
2
        fn check<T: PartialOrd>(last: &mut T) -> impl FnMut(T) -> bool + '_ {
1687
617
            move |curr| {
1688
617
                if let Some(Ordering::Greater) | None = (*last).partial_cmp(&curr) {
1689
0
                    return false;
1690
617
                }
1691
617
                *last = curr;
1692
617
                true
1693
617
            }
1694
2
        }
1695
1696
1
        let instance_info = Default::default();
1697
1
        let device_commands =
1698
1
            Global::<TestLayer>::instance().create_device_commands(&instance_info, None);
1699
1
        let mut name_iter = device_commands
1700
1
            .iter()
1701
517
            .map(|VulkanCommand { name, .. }| *name);
1702
1
        let mut last = name_iter.next().unwrap();
1703
1
1704
1
        assert!(name_iter.all(check(&mut last)));
1705
1706
1
        let instance_commands =
1707
1
            Global::<TestLayer>::instance().create_instance_commands(&instance_info);
1708
1
        let mut name_iter = instance_commands
1709
1
            .iter()
1710
102
            .map(|VulkanCommand { name, .. }| *name);
1711
1
        let mut last = name_iter.next().unwrap();
1712
1
1713
1
        assert!(name_iter.all(check(&mut last)));
1714
1
    }
1715
1716
    #[test]
1717
1
    fn fill_vk_out_array_should_handle_zero_count_correctly() {
1718
1
        let extensions = [ExtensionProperties {
1719
1
            name: Extension::KHRSwapchain,
1720
1
            spec_version: 1,
1721
1
        }]
1722
1
        .into_iter()
1723
1
        .map(Into::<vk::ExtensionProperties>::into)
1724
1
        .collect::<Vec<_>>();
1725
1
1726
1
        let mut count = 0;
1727
1
        assert_eq!(
1728
1
            unsafe { fill_vk_out_array(&extensions, (&mut count).into(), null_mut()) },
1729
1
            vk::Result::SUCCESS
1730
1
        );
1731
1
        assert_eq!(count, extensions.len());
1732
1733
1
        count = 0;
1734
1
        let mut extension_property = MaybeUninit::<vk::ExtensionProperties>::uninit();
1735
1
        assert_eq!(
1736
1
            unsafe {
1737
1
                fill_vk_out_array(
1738
1
                    &extensions,
1739
1
                    (&mut count).into(),
1740
1
                    extension_property.as_mut_ptr(),
1741
1
                )
1742
1
            },
1743
1
            vk::Result::INCOMPLETE
1744
1
        );
1745
1
        assert_eq!(count, 0);
1746
1747
1
        count = 0;
1748
1
        assert_eq!(
1749
1
            unsafe { fill_vk_out_array(&[], (&mut count).into(), extension_property.as_mut_ptr()) },
1750
1
            vk::Result::SUCCESS
1751
1
        );
1752
1
    }
1753
1754
    #[test]
1755
1
    fn fill_vk_out_array_should_return_incomplete_with_short_out_array() {
1756
1
        let extensions = [
1757
1
            ExtensionProperties {
1758
1
                name: Extension::KHRSwapchain,
1759
1
                spec_version: 1,
1760
1
            },
1761
1
            ExtensionProperties {
1762
1
                name: Extension::KHRSamplerYcbcrConversion,
1763
1
                spec_version: 1,
1764
1
            },
1765
1
        ]
1766
1
        .into_iter()
1767
1
        .map(Into::<vk::ExtensionProperties>::into)
1768
1
        .collect::<Vec<_>>();
1769
1
1770
1
        let mut count = 1;
1771
1
        let mut extension_property = MaybeUninit::<vk::ExtensionProperties>::uninit();
1772
1
        assert_eq!(
1773
1
            unsafe {
1774
1
                fill_vk_out_array(
1775
1
                    &extensions,
1776
1
                    (&mut count).into(),
1777
1
                    extension_property.as_mut_ptr(),
1778
1
                )
1779
1
            },
1780
1
            vk::Result::INCOMPLETE
1781
1
        );
1782
1
        assert_eq!(count, 1);
1783
1
    }
1784
}